package rexsee.multimedia;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import rexsee.core.browser.Browser;
import rexsee.core.browser.RexseeUrl;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.utilities.Utilities;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;

public class RexseeAudioPlayer implements JavascriptInterface {

	public static final String INTERFACE_NAME = "AudioPlayer";
	@Override
	public String getInterfaceName() {
		return mBrowser.application.resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return this;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeAudioPlayer(childBrowser);
	}

	public static final String DEFAULT_ID = "default";

	public static final String EVENT_ONAUDIOBUFFERINGUPDATED = "onAudioBufferingUpdated";
	public static final String EVENT_ONAUDIOPLAYCOMPLETED = "onAudioPlayCompleted";
	public static final String EVENT_ONAUDIOPLAYERINFO = "onAudioPlayerInfo";
	public static final String EVENT_ONAUDIOSEEKCOMPLETED = "onAudioSeekCompleted";

	private final Browser mBrowser;
	private final Context mContext;
	private final HashMap<String, MediaPlayer> mMap;

	public RexseeAudioPlayer(Browser browser) {
		mBrowser = browser;
		mContext = browser.getContext();
		mMap = new HashMap<String, MediaPlayer>();
		mBrowser.eventList.add(EVENT_ONAUDIOBUFFERINGUPDATED);
		mBrowser.eventList.add(EVENT_ONAUDIOPLAYCOMPLETED);
		mBrowser.eventList.add(EVENT_ONAUDIOPLAYERINFO);
		mBrowser.eventList.add(EVENT_ONAUDIOSEEKCOMPLETED);
		mBrowser.destroyListeners.add(new Runnable() {
			@Override
			public void run() {
				stop();
			}
		});
	}

	//JavaScript Interface
	public int size() {
		return mMap.size();
	}
	public String getIds() {
		String rtn = "";
		Set<String> ids = mMap.keySet();
		Iterator<String> iterator = ids.iterator();
		while (iterator.hasNext()) {
			if (!rtn.equals("")) rtn += ",";
			rtn += "\"" + iterator.next() + "\"";
		}
		return "[" + rtn + "]";
	}

	public boolean start(String url, boolean looping) {
		return start(DEFAULT_ID, url, looping);
	}
	public boolean start(final String id, String url, boolean looping) {
		url = mBrowser.urlListeners.getAbsoluteUrl(url);
		stop(id);
		try {
			MediaPlayer player = new MediaPlayer();
			player.setLooping(looping);
			player.setAudioStreamType(AudioManager.STREAM_MUSIC);
			player.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
				@Override
				public void onBufferingUpdate(MediaPlayer mp, int percent) {
					mBrowser.eventList.run(EVENT_ONAUDIOBUFFERINGUPDATED, new String[]{id, String.valueOf(percent)});
				}
			});
			player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
				@Override
				public void onCompletion(MediaPlayer mp) {
					stop(id);
					mBrowser.eventList.run(EVENT_ONAUDIOPLAYCOMPLETED, new String[]{id});
				}
			});
			player.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
				@Override
				public void onSeekComplete(MediaPlayer mp) {
					mBrowser.eventList.run(EVENT_ONAUDIOSEEKCOMPLETED, new String[]{id});
				}
			});
			player.setOnErrorListener(new MediaPlayer.OnErrorListener() {
				@Override
				public boolean onError(MediaPlayer mp, int what, int extra) {
					String msg;
					switch (what) {
						case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK :
							msg = "MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK";
							break;
						case MediaPlayer.MEDIA_ERROR_SERVER_DIED :
							msg = "MEDIA_ERROR_SERVER_DIED";
							break;
						case MediaPlayer.MEDIA_ERROR_UNKNOWN :
							msg = "MEDIA_ERROR_UNKNOWN";
							break;
						default :
							msg = "MEDIA_ERROR_UNKNOWN";
							break;
					}
					mBrowser.exception(getInterfaceName(), msg);
					return false;
				}
			});
			player.setOnInfoListener(new MediaPlayer.OnInfoListener() {
				@Override
				public boolean onInfo(MediaPlayer mp, int what, int extra) {
					String msg;
					switch (what) {
						case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING :
							msg = "MEDIA_INFO_BAD_INTERLEAVING";
							break;
						case MediaPlayer.MEDIA_INFO_METADATA_UPDATE :
							msg = "MEDIA_INFO_METADATA_UPDATE";
							break;
						case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE :
							msg = "MEDIA_INFO_NOT_SEEKABLE";
							break;
						case MediaPlayer.MEDIA_INFO_UNKNOWN :
							msg = "MEDIA_INFO_UNKNOWN";
							break;
						case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING :
							msg = "MEDIA_INFO_VIDEO_TRACK_LAGGING";
							break;
						default :
							msg = "MEDIA_INFO_UNKNOWN";
							break;
					}
					mBrowser.eventList.run(EVENT_ONAUDIOPLAYERINFO, new String[]{id, msg});
					return false;
				}
			});
			player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
				@Override
				public void onPrepared(MediaPlayer mp) {
					mp.start();
				}
			});
			String lUrl = url.toLowerCase();
			if (lUrl.startsWith(RexseeUrl.ASSET_URL)) {
				url = url.replace(RexseeUrl.ASSET_URL, "");
				AssetFileDescriptor file = mContext.getResources().getAssets().openFd(url);
				player.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
				file.close();
				player.prepareAsync();
				mMap.put(id, player);
				return true;
			} else if (lUrl.startsWith("file://")) {
				File file = Utilities.prepareReadFile(url);
				if (file == null) {
					mBrowser.exception(getInterfaceName(), "The audio file doesn't exist.");
					return false;
				}
				url = file.getAbsolutePath();
				player.setDataSource(url);
				player.prepareAsync();
				mMap.put(id, player);
				return true;
			} else if (lUrl.startsWith("http://") || lUrl.startsWith("https://") || lUrl.startsWith("rtsp://")) {
				player.setDataSource(url);
				player.prepareAsync();
				mMap.put(id, player);
				return true;
			} else {
				mBrowser.exception(getInterfaceName(), "Invalid file path.");
				return false;
			}
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	public void stop() {
		stop(DEFAULT_ID);
	}
	public void stop(String id) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return;
		try {
			player.stop();
			player.release();
			player = null;
			mMap.remove(id);
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
		}
	}
	public void stopAll() {
		Set<String> ids = mMap.keySet();
		Iterator<String> iterator = ids.iterator();
		while (iterator.hasNext()) {
			MediaPlayer player = mMap.get(iterator.next());
			try {
				player.stop();
				player.release();
				player = null;
			} catch (Exception e) {
			}
		}
		mMap.clear();
	}

	public void pause() {
		pause(DEFAULT_ID);
	}
	public void pause(String id) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return;
		try {
			player.pause();
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
		}
	}
	public void resume() {
		resume(DEFAULT_ID);
	}
	public void resume(String id) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return;
		try {
			player.start();
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
		}
	}
	public void seekTo(int milliseconds) {
		seekTo(DEFAULT_ID, milliseconds);
	}
	public void seekTo(String id, int milliseconds) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return;
		try {
			player.seekTo(milliseconds);
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
		}
	}
	public int getDuration() {
		return getDuration(DEFAULT_ID);
	}
	public int getDuration(String id) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return -1;
		try {
			return player.getDuration();
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return -1;
		}
	}
	public int getCurrentPosition() {
		return getCurrentPosition(DEFAULT_ID);
	}
	public int getCurrentPosition(String id) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return -1;
		try {
			return player.getCurrentPosition();
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return -1;
		}
	}
	public boolean isLooping() {
		return isLooping(DEFAULT_ID);
	}
	public boolean isLooping(String id) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return false;
		return player.isLooping();
	}
	public boolean isPlaying() {
		return isPlaying(DEFAULT_ID);
	}
	public boolean isPlaying(String id) {
		MediaPlayer player = mMap.get(id);
		if (player == null) return false;
		return player.isPlaying();
	}

	public boolean setVolume(float volume) {
		if (volume < 0 || volume > 1) {
			mBrowser.exception(getInterfaceName(), "The volumn must between 0 and 1.");
			return false;
		}
		AudioManager mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
		mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, Math.round((mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * volume)), 0);
		return true;
	}

}
